// 流式TTS服务 - 基于WebSocket的实时语音合成
import config from '@/config.js';
import { ttsErrorHandler, ttsPlayWithErrorHandling, fallbackToBrowserTts } from './ttsErrorHandler.js';

/**
 * 流式TTS配置
 */
const STREAMING_CONFIG = {
  wsUrl: 'wss://openspeech.bytedance.com/api/v1/tts/ws_binary',
  timeout: 60000, // 60秒超时
  retryCount: 3, // 重试次数
  retryDelay: 1000, // 重试延迟
};

/**
 * 流式TTS客户端类
 */
class StreamingTtsClient {
  constructor() {
    this.ws = null;
    this.audioBuffer = [];
    this.isConnected = false;
    this.isPlaying = false;
    this.currentRequest = null;
    this.eventListeners = new Map();
    this.audioContext = null;
    this.audioQueue = [];
  }

  /**
   * 初始化音频上下文
   */
  async initAudioContext() {
    if (!this.audioContext) {
      this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
      if (this.audioContext.state === 'suspended') {
        await this.audioContext.resume();
      }
    }
    return this.audioContext;
  }

  /**
   * 添加事件监听器
   */
  on(event, callback) {
    if (!this.eventListeners.has(event)) {
      this.eventListeners.set(event, []);
    }
    this.eventListeners.get(event).push(callback);
  }

  /**
   * 移除事件监听器
   */
  off(event, callback) {
    if (this.eventListeners.has(event)) {
      const listeners = this.eventListeners.get(event);
      const index = listeners.indexOf(callback);
      if (index > -1) {
        listeners.splice(index, 1);
      }
    }
  }

  /**
   * 触发事件
   */
  emit(event, data) {
    if (this.eventListeners.has(event)) {
      this.eventListeners.get(event).forEach(callback => {
        try {
          callback(data);
        } catch (error) {
          console.error(`事件监听器错误 [${event}]:`, error);
        }
      });
    }
  }

  /**
   * 连接WebSocket
   */
  async connect() {
    return new Promise((resolve, reject) => {
      try {
        const accessToken = config?.tts?.accessToken;
        if (!accessToken) {
          reject(new Error('TTS accessToken未配置'));
          return;
        }

        // 根据火山引擎文档，WebSocket认证使用URL参数
        const wsUrl = `${STREAMING_CONFIG.wsUrl}?access_token=${encodeURIComponent(accessToken)}`;
        console.log('[StreamingTTS] 连接URL:', wsUrl.replace(accessToken, '***'));
        this.ws = new WebSocket(wsUrl);
        this.ws.binaryType = 'arraybuffer';

        const timeout = setTimeout(() => {
          if (!this.isConnected) {
            this.ws.close();
            reject(new Error('连接超时'));
          }
        }, 10000);

        this.ws.onopen = () => {
          clearTimeout(timeout);
          this.isConnected = true;
          console.log('[StreamingTTS] WebSocket连接已建立');
          this.emit('connected');
          resolve();
        };

        this.ws.onclose = (event) => {
          clearTimeout(timeout);
          this.isConnected = false;
          console.log('[StreamingTTS] WebSocket连接已关闭:', event.code, event.reason);
          this.emit('disconnected', { code: event.code, reason: event.reason });
        };

        this.ws.onerror = (error) => {
          clearTimeout(timeout);
          console.error('[StreamingTTS] WebSocket错误:', error);
          this.emit('error', error);
          reject(error);
        };

        this.ws.onmessage = (event) => {
          this.handleMessage(event);
        };

      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 处理WebSocket消息
   */
  handleMessage(event) {
    try {
      const arrayBuffer = event.data instanceof ArrayBuffer ? event.data : event.data.buffer;
      const data = new Uint8Array(arrayBuffer);

      // 解析消息头
      const protocolVersion = (data[0] & 0xff) >> 4;
      const headerSize = data[0] & 0x0f;
      const messageType = (data[1] & 0xff) >> 4;
      const messageTypeSpecificFlags = data[1] & 0x0f;

      console.log('[StreamingTTS] 收到消息:', { 
        protocolVersion, 
        headerSize, 
        messageType, 
        messageTypeSpecificFlags 
      });

      if (messageType === 11) {
        // 音频数据响应
        this.handleAudioResponse(arrayBuffer, headerSize, messageTypeSpecificFlags);
      } else if (messageType === 15) {
        // 错误消息
        this.handleErrorMessage(arrayBuffer, headerSize);
      } else {
        console.warn('[StreamingTTS] 未知消息类型:', messageType);
      }

    } catch (error) {
      console.error('[StreamingTTS] 处理消息失败:', error);
      this.emit('error', error);
    }
  }

  /**
   * 处理音频数据响应
   */
  async handleAudioResponse(arrayBuffer, headerSize, flags) {
    if (flags === 0) {
      // ACK响应，无音频数据
      console.log('[StreamingTTS] 收到ACK响应');
      return;
    }

    try {
      const offset = headerSize * 4;
      const sequenceNumber = new DataView(arrayBuffer, offset, 4).getInt32(0, false);
      const payloadSize = new DataView(arrayBuffer, offset + 4, 4).getInt32(0, false);
      const audioData = new Uint8Array(arrayBuffer, offset + 8, payloadSize);

      console.log('[StreamingTTS] 收到音频数据:', { 
        sequenceNumber, 
        payloadSize, 
        audioDataLength: audioData.length 
      });

      // 累积音频数据
      this.audioBuffer.push(...audioData);

      // 流式播放：收到数据立即播放
      if (audioData.length > 0) {
        await this.playAudioChunk(audioData);
      }

      // 序列号小于0表示最后一段
      if (sequenceNumber < 0) {
        console.log('[StreamingTTS] 流式TTS播放完成');
        this.emit('completed', { totalSize: this.audioBuffer.length });
        this.close();
      }

    } catch (error) {
      console.error('[StreamingTTS] 处理音频数据失败:', error);
      this.emit('error', error);
    }
  }

  /**
   * 处理错误消息
   */
  handleErrorMessage(arrayBuffer, headerSize) {
    try {
      const offset = headerSize * 4;
      const code = new DataView(arrayBuffer, offset, 4).getInt32(0, false);
      const messageSize = new DataView(arrayBuffer, offset + 4, 4).getInt32(0, false);
      const errorMessage = new TextDecoder().decode(
        new Uint8Array(arrayBuffer, offset + 8, messageSize)
      );

      console.error('[StreamingTTS] TTS服务错误:', code, errorMessage);
      this.emit('error', { code, message: errorMessage });
      this.close();

    } catch (error) {
      console.error('[StreamingTTS] 解析错误消息失败:', error);
      this.emit('error', error);
    }
  }

  /**
   * 播放音频块
   */
  async playAudioChunk(audioData) {
    try {
      await this.initAudioContext();

      // 创建音频blob
      const blob = new Blob([audioData], { type: 'audio/mpeg' });
      const arrayBuffer = await blob.arrayBuffer();
      
      // 解码音频数据
      const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
      
      // 创建音频源
      const source = this.audioContext.createBufferSource();
      source.buffer = audioBuffer;
      source.connect(this.audioContext.destination);
      
      // 播放音频
      source.start();
      
      console.log('[StreamingTTS] 音频块开始播放:', { size: audioData.length });
      this.emit('chunkPlayed', { size: audioData.length });

    } catch (error) {
      console.warn('[StreamingTTS] 播放音频块失败:', error);
      // 降级到HTML5 Audio
      this.playAudioChunkFallback(audioData);
    }
  }

  /**
   * 降级播放方法
   */
  playAudioChunkFallback(audioData) {
    try {
      const blob = new Blob([audioData], { type: 'audio/mpeg' });
      const url = URL.createObjectURL(blob);
      
      const audio = new Audio(url);
      audio.preload = 'auto';
      audio.playsInline = true;
      audio.volume = 0.8;
      
      audio.onended = () => {
        URL.revokeObjectURL(url);
      };
      
      audio.onerror = (err) => {
        console.warn('[StreamingTTS] 降级播放错误:', err);
        URL.revokeObjectURL(url);
      };
      
      audio.play().catch(err => {
        console.warn('[StreamingTTS] 降级播放失败:', err);
        URL.revokeObjectURL(url);
      });
      
    } catch (error) {
      console.warn('[StreamingTTS] 降级播放失败:', error);
    }
  }

  /**
   * 发送合成请求
   */
  async synthesize(text, options = {}) {
    if (!this.isConnected) {
      await this.connect();
    }

    return new Promise((resolve, reject) => {
      try {
        this.currentRequest = { resolve, reject };
        this.audioBuffer = [];

        // 构建请求数据
        const request = {
          app: {
            appid: config?.tts?.appId,
            cluster: config?.tts?.cluster || 'volcano_tts'
          },
          user: {
            uid: 'streaming_user_' + Date.now()
          },
          audio: {
            voice_type: options.voiceType || config?.tts?.defaultVoice || 'zh_female_kefunvsheng_mars_bigtts',
            encoding: options.encoding || 'mp3',
            speed_ratio: options.speedRatio || 1.0,
            volume_ratio: options.volumeRatio || 1.0,
            pitch_ratio: options.pitchRatio || 1.0,
            ...(options.emotion && { emotion: options.emotion }),
            ...(options.language && { language: options.language })
          },
          request: {
            reqid: Date.now().toString(),
            operation: 'submit',
            text: text,
            ...(options.textType && { text_type: options.textType }),
            ...(options.silenceDuration && { silence_duration: options.silenceDuration })
          }
        };

        // 发送请求
        const jsonData = JSON.stringify(request);
        const jsonBytes = new TextEncoder().encode(jsonData);
        
        // 构建二进制消息
        const header = new Uint8Array([0x11, 0x10, 0x10, 0x00]);
        const payloadSizeBuffer = new ArrayBuffer(4);
        const payloadSizeView = new DataView(payloadSizeBuffer);
        payloadSizeView.setUint32(0, jsonBytes.length, false); // 大端序
        const payloadSize = new Uint8Array(payloadSizeBuffer);
        
        const message = new Uint8Array(8 + jsonBytes.length);
        message.set(header, 0);
        message.set(payloadSize, 4);
        message.set(jsonBytes, 8);
        
        console.log('[StreamingTTS] 发送合成请求:', { text, messageLength: message.length });
        this.ws.send(message);
        
        this.emit('synthesizeStarted', { text, options });

        // 设置超时
        setTimeout(() => {
          if (this.currentRequest) {
            this.currentRequest.reject(new Error('合成超时'));
            this.currentRequest = null;
          }
        }, STREAMING_CONFIG.timeout);

      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 关闭连接
   */
  close() {
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
    this.isConnected = false;
    
    if (this.currentRequest) {
      this.currentRequest.resolve({ audioBuffer: this.audioBuffer });
      this.currentRequest = null;
    }
  }

  /**
   * 销毁客户端
   */
  destroy() {
    this.close();
    this.eventListeners.clear();
    this.audioBuffer = [];
  }
}

/**
 * 流式TTS服务单例
 */
class StreamingTtsService {
  constructor() {
    this.client = null;
    this.isInitialized = false;
  }

  /**
   * 初始化服务
   */
  async init() {
    if (this.isInitialized) return;
    
    this.client = new StreamingTtsClient();
    this.isInitialized = true;
    
    console.log('[StreamingTTS] 服务已初始化');
  }

  /**
   * 合成并播放文本
   */
  async synthesizeAndPlay(text, options = {}) {
    if (!this.isInitialized) {
      await this.init();
    }

    return new Promise((resolve, reject) => {
      const client = this.client;
      
      // 设置事件监听器
      const onCompleted = (data) => {
        client.off('completed', onCompleted);
        client.off('error', onError);
        resolve(data);
      };
      
      const onError = (error) => {
        client.off('completed', onCompleted);
        client.off('error', onError);
        
        // 使用错误处理器处理错误
        const errorAction = ttsErrorHandler.handleError(error, { text, options });
        
        if (errorAction.action === 'fallback' && errorAction.fallback) {
          // 降级到浏览器TTS
          fallbackToBrowserTts(text, options)
            .then(resolve)
            .catch(fallbackError => {
              console.error('[StreamingTTS] 降级播放也失败:', fallbackError);
              reject(new Error(`流式TTS失败: ${error.message}, 降级播放也失败: ${fallbackError.message}`));
            });
        } else {
          reject(error);
        }
      };
      
      client.on('completed', onCompleted);
      client.on('error', onError);
      
      // 开始合成
      client.synthesize(text, options).catch(reject);
    });
  }

  /**
   * 销毁服务
   */
  destroy() {
    if (this.client) {
      this.client.destroy();
      this.client = null;
    }
    this.isInitialized = false;
  }
}

// 创建全局服务实例
const streamingTtsService = new StreamingTtsService();

export default streamingTtsService;
export { StreamingTtsClient, StreamingTtsService };
